﻿//////////////////////////////////////////////////////////////////////////////
//
//  Copyright © 1998-2024 Glodon Company Limited.  All rights reserved.
//
//  Use of this software is subject to the terms of the Glodon license
//  agreement provided at the time of installation or download, or which
//  otherwise accompanies this software in either electronic or hard copy form.  
//
//////////////////////////////////////////////////////////////////////////////

// NotReviewedButNeeded
#pragma once

#include "GcmpDatabase.h"
#include <map>
#include <vector>
#include <unordered_map>
#include "NdbObject.h"

namespace gcmp
{
    class ElementId;
    struct ElementIdHash;
    class NdbDatabase;
    class NdbClassSchema;
    class NdbObjectSchematic;
    class NdbElement;
    class NdbPropertySchema;

    /// \brief 获取给定对象所有的类型为ElementId的属性及其嵌套属性的参数
    /// \see NdbDataInterface::GetReferencedElementIds()
    struct GCMP_DATABASE_EXPORT GetReferencedElementIdsParams
    {
        const NdbObjectSchematic * Object;
        std::set<ElementId> * ElementIds;
        std::unordered_map<ElementId, std::vector<std::wstring>, ElementIdHash> * Paths;
        std::vector<std::wstring>* CurrentPath;
    };

    /// \brief Ndb数据访问接口。
    ///
    /// 方便对NdbObject进行取值和赋值
    class GCMP_DATABASE_EXPORT NdbDataInterface
    {
    public:
        /// \brief     获取给定对象所有的类型为ElementId的属性及其嵌套属性。结果添加到pElementIds里
        static void GetReferencedElementIds(
            const NdbObjectSchematic * pObject, 
            std::set<ElementId> * pElementIds,
            std::unordered_map<ElementId, std::vector<std::wstring>, ElementIdHash> * pPaths = nullptr,
            std::vector<std::wstring>* pCurrentPath = nullptr
        );

        /// \brief 获取给定对象所有的类型为ElementId的属性及其嵌套属性。结果添加到pElementIds里
        /// \param params 参数。参见GetReferencedElementIdsParams
        static void GetReferencedElementIds(GetReferencedElementIdsParams & params);

        /// \brief     检查对象是否含有类型为ElementId的属性及其嵌套属性
        static bool DetectElementId(const NdbObjectSchematic * pObject);

        /// \brief     将对象是类型为ElementId的属性及其嵌套属性替换成oldToNewMap里的对应项
        static void ReplaceElementIds(
            NdbObjectSchematic * pObject,
            const std::unordered_map<ElementId, ElementId, ElementIdHash> & oldToNewMap
        );

        /// \brief     根据id和propertyName检查对象指定的属性是否存在；若存在，对象地址放入pObject中，属性的Schema放入propertySchema中
        /// \return    bool    返回false时表示参数不合法，可能是参数不合法，或者对象不存在，或者对象的属性不存在
        static bool CheckNdbProperty(
            NdbDatabase * pDatabase,
            const ElementId & id, 
            const std::wstring & propertyName,
            const NdbElement *& pElement,
            NdbPropertySchema & propertySchema
        );

        /// \brief     获取NdbObject的模块组
        /// \return    获得的模块组Guid
        static Guid GetModuleGroupOfNdbObject(
            const NdbObject* pNdbObject
        );

        /// \brief     获取NdbObject及其所有属性(包括嵌套的属性的属性)ModuleGroups
        /// \return    void
        static void CollectModuleGroupsOfNdbObject(
            const NdbObject* pNdbObject,
            std::set<Guid, GuidComparer>& moduleGroupsGuids
        );

        /// \brief     获得NdbObject正确的ModuleGroup(专业)并进行检查
        ///
        /// 如果NdbObject中有属性(包括属性的属性)属于当前专业的后置专业，则toSetModuleGroup为此后置专业
        /// 如果NdbObject中有属性(包括属性的属性)属于当前专业的多个后置专业，且多个后置专业之间没有依赖关系，则报错
        /// \return    bool    返回false时表示检查有错误，true表示无错误
        static bool GetRightModuleGroupsOfNdbObject(
            const NdbObject* pNdbObject,
            Guid& toSetModuleGroup
        );

    private:
        static void GetReferencedElementIdsImpl(const NdbObjectSchematic* pObject, const NdbClassSchema* pClassSchema, std::set<ElementId>* pElementIds
            , std::unordered_map<ElementId, std::vector<std::wstring>, ElementIdHash>* pPaths = nullptr, std::vector<std::wstring>* pCurrentPath = nullptr);

        static void GetReferencedElementIdsImpl(
            const NdbClassSchema* pClassSchema, 
            GetReferencedElementIdsParams & params
        );

        static bool DetectElementIdImpl(const NdbObjectSchematic* pObject, const NdbClassSchema* pClassSchema);
        static void ReplaceElementIdsImpl(NdbObjectSchematic* pObject, const NdbClassSchema* pClassSchema, const std::unordered_map<ElementId, ElementId, ElementIdHash>& oldToNewMap);
    };
}

